/*
 * @Authoryour name
 * @Date2020-12-17 23:14:30
 * @LastEditTime2020-12-17 23:15:33
 * @LastEditorsyour name
 * @DescriptionIn User Settings Edit
 * @FilePath\STM32H750_FreeRTOS\Bsp\bsp_sdram\bsp_sdram.c
 */ 
#include "bsp_fmc_sdram.h"

static SDRAM_HandleTypeDef sdram_handle;

static void _fmc_sdram_gpio_init(void);
static void _fmc_sdram_module_init(void);
static void _fmc_sdram_w9825g6kh_init(void);
static void _fmc_sdram_delay(uint32_t time);

/**
 * @brief  
 * @param  
 * @retval 
 */
void bsp_fmc_sdram_init(void)
{
    _fmc_sdram_gpio_init();
    _fmc_sdram_module_init();
    _fmc_sdram_w9825g6kh_init();
}

void bsp_fmc_sdram_test(void)
{
    uint32_t addr = 0xC0000000;
    uint16_t data = 0;
    uint32_t i, start_time, time_cast;
    printf("==========================================\r\n");
    printf("FMC SDRAM Test Start!\r\n\r\n");

    /* write data */
    printf("Writing the %ld bytes data, waiting....\r\n", SDRAM_SIZE);
    start_time = HAL_GetTick();
    for (i = 0; i < SDRAM_SIZE / 2; i++)
    {
        *(volatile uint16_t *)(SDRAM_BANK_ADDR + i * 2) = (uint16_t)0x5555;
    }
    time_cast = HAL_GetTick() - start_time;
    printf("Write data success, total time: %d.%03dS.\r\n", time_cast / 1000,
          time_cast % 1000 / ((1000 * 1 + 999) / 1000));

    for (i = 0; i < SDRAM_SIZE / 2; i++)
    {
        data = *(__IO uint16_t *)(SDRAM_BANK_ADDR + i * 2);
        if (data != 0x5555)
        {
            printf("SDRAM test failed!\r\n");
            break;
        }
    }

    printf("\r\nFMC SDRAM Test End!\r\n");
    printf("==========================================\r\n");
}

static void _fmc_sdram_w9825g6kh_init(void)
{
    FMC_SDRAM_CommandTypeDef sdram_cmd;
    /* #10 */
    sdram_cmd.CommandMode            = FMC_SDRAM_CMD_CLK_ENABLE;
    sdram_cmd.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK1;
    sdram_cmd.AutoRefreshNumber      = 1;
    sdram_cmd.ModeRegisterDefinition = 0;
    HAL_SDRAM_SendCommand(&sdram_handle, &sdram_cmd, 100);
    /* #20 */
    _fmc_sdram_delay(0xFFFFFF);
    /* #30 */
    sdram_cmd.CommandMode            = FMC_SDRAM_CMD_PALL;
    sdram_cmd.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK1;
    sdram_cmd.AutoRefreshNumber      = 1;
    sdram_cmd.ModeRegisterDefinition = 0;
    HAL_SDRAM_SendCommand(&sdram_handle, &sdram_cmd, 100);
    /* #40 */
    sdram_cmd.CommandMode            = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
    sdram_cmd.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK1;
    sdram_cmd.AutoRefreshNumber      = 8;
    sdram_cmd.ModeRegisterDefinition = 0;
    HAL_SDRAM_SendCommand(&sdram_handle, &sdram_cmd, 100);
    /* #50 */
    sdram_cmd.CommandMode            = FMC_SDRAM_CMD_LOAD_MODE;
    sdram_cmd.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK1;
    sdram_cmd.AutoRefreshNumber      = 1;
    sdram_cmd.ModeRegisterDefinition = SDRAM_MODEREG_BURST_LENGTH_2 |
                                       SDRAM_MODEREG_ADDR_MODE_SEQUENTIAL |
                                       SDRAM_MODEREG_CAS_LATENCY_2 |
                                       SDRAM_MODEREG_BURST_READ_SINGLE_WRITE;
    HAL_SDRAM_SendCommand(&sdram_handle, &sdram_cmd, 100);
    /* #60 */
    HAL_SDRAM_ProgramRefreshRate(&sdram_handle, 677);
}

/**
 * @brief  
 * @param  
 * @retval 
 */
static void _fmc_sdram_module_init(void)
{
    FMC_SDRAM_TimingTypeDef sdram_time; 

    /* Enable Clock */
    FMC_SDRAM_CLK_EN();

    sdram_handle.Instance                = FMC_SDRAM_DEVICE;
    sdram_handle.Init.SDBank             = FMC_SDRAM_BANK1;
    sdram_handle.Init.ColumnBitsNumber   = FMC_SDRAM_COLUMN_BITS_NUM_9;
    sdram_handle.Init.RowBitsNumber      = FMC_SDRAM_ROW_BITS_NUM_13;
    sdram_handle.Init.MemoryDataWidth    = FMC_SDRAM_MEM_BUS_WIDTH_16;
    sdram_handle.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
    sdram_handle.Init.CASLatency         = FMC_SDRAM_CAS_LATENCY_2;
    sdram_handle.Init.WriteProtection    = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
    sdram_handle.Init.SDClockPeriod      = FMC_SDRAM_CLOCK_PERIOD_2;
    sdram_handle.Init.ReadBurst          = FMC_SDRAM_RBURST_ENABLE;
    sdram_handle.Init.ReadPipeDelay      = FMC_SDRAM_RPIPE_DELAY_0;

    sdram_time.LoadToActiveDelay = 2;
    sdram_time.ExitSelfRefreshDelay = 8;
    sdram_time.SelfRefreshTime   = 6;
    sdram_time.RowCycleDelay     = 6;
    sdram_time.WriteRecoveryTime = 2;
    sdram_time.RCDDelay          = 2;
    sdram_time.RPDelay           = 2;

    if(HAL_SDRAM_Init(&sdram_handle, &sdram_time) != HAL_OK)
    {
        ExprAssertCalled(__FILE__, __LINE__);
    }
}



/**
 * @brief  
 * @param  
 * @retval 
 */
static void _fmc_sdram_gpio_init(void)
{
    GPIO_InitTypeDef gpio_init;

    FMC_SDRAM_GPIO_CLK_EN();
    /* FMC A0 ~ A9 */
    gpio_init.Alternate = GPIO_AF12_FMC;
    gpio_init.Pin = (FMC_SDRAM_A0_PIN |
                     FMC_SDRAM_A1_PIN |
                     FMC_SDRAM_A2_PIN |
                     FMC_SDRAM_A3_PIN |
                     FMC_SDRAM_A4_PIN |
                     FMC_SDRAM_A5_PIN |
                     FMC_SDRAM_A6_PIN |
                     FMC_SDRAM_A7_PIN |
                     FMC_SDRAM_A8_PIN |
                     FMC_SDRAM_A9_PIN);
    gpio_init.Mode = GPIO_MODE_AF_PP;
    gpio_init.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(FMC_SDRAM_A0_9_PORT, &gpio_init);
    /* FMC A10 ~ A12 */
    gpio_init.Alternate = GPIO_AF12_FMC;
    gpio_init.Pin = (FMC_SDRAM_A10_PIN |
                     FMC_SDRAM_A11_PIN |
                     FMC_SDRAM_A12_PIN);
    HAL_GPIO_Init(FMC_SDRAM_A10_12_PORT, &gpio_init);
    /* FMC D0 ~ D3, D13 ~ D15 */
    gpio_init.Alternate = GPIO_AF12_FMC;
    gpio_init.Pin = (FMC_SDRAM_D0_PIN |
                     FMC_SDRAM_D1_PIN |
                     FMC_SDRAM_D2_PIN |
                     FMC_SDRAM_D3_PIN |
                     FMC_SDRAM_D13_PIN |
                     FMC_SDRAM_D14_PIN |
                     FMC_SDRAM_D15_PIN);
    HAL_GPIO_Init(FMC_SDRAM_D0_3_13_15_PORT, &gpio_init);
    /* FMC D4 ~ D12 */
    gpio_init.Alternate = GPIO_AF12_FMC;
    gpio_init.Pin = (FMC_SDRAM_D4_PIN |
                     FMC_SDRAM_D5_PIN |
                     FMC_SDRAM_D6_PIN |
                     FMC_SDRAM_D7_PIN |
                     FMC_SDRAM_D8_PIN |
                     FMC_SDRAM_D9_PIN |
                     FMC_SDRAM_D10_PIN |
                     FMC_SDRAM_D11_PIN |
                     FMC_SDRAM_D12_PIN);
    HAL_GPIO_Init(FMC_SDRAM_D4_12_PORT, &gpio_init);
    /* FMC BA */
    gpio_init.Alternate = GPIO_AF12_FMC;
    gpio_init.Pin = (FMC_SDRAM_BA0_PIN | FMC_SDRAM_BA1_PIN);
    HAL_GPIO_Init(FMC_SDRAM_BA_PORT, &gpio_init);
    /* FMC NBL */
    gpio_init.Alternate = GPIO_AF12_FMC;
    gpio_init.Pin = (FMC_SDRAM_NBL0_PIN | FMC_SDRAM_NBL1_PIN);
    HAL_GPIO_Init(FMC_SDRAM_NBL_PORT, &gpio_init);
    /* FMC SDNE */
    gpio_init.Alternate = GPIO_AF12_FMC;
    gpio_init.Pin = FMC_SDRAM_SDCKE0_PIN;
    HAL_GPIO_Init(FMC_SDRAM_SDCKE0_PORT, &gpio_init);
    /* FMC SDCKE0 */
    gpio_init.Alternate = GPIO_AF12_FMC;
    gpio_init.Pin = FMC_SDRAM_SDCKE0_PIN;
    HAL_GPIO_Init(FMC_SDRAM_SDCKE0_PORT, &gpio_init);
    /* FMC SDNCAS */
    gpio_init.Alternate = GPIO_AF12_FMC;
    gpio_init.Pin = FMC_SDRAM_SDNCAS_PIN;
    HAL_GPIO_Init(FMC_SDRAM_SDNCAS_PORT, &gpio_init);
    /* FMC SDNRAS */
    gpio_init.Alternate = GPIO_AF12_FMC;
    gpio_init.Pin = FMC_SDRAM_SDNRAS_PIN;
    HAL_GPIO_Init(FMC_SDRAM_SDNRAS_PORT, &gpio_init);
    /* FMC SDNWE */
    gpio_init.Alternate = GPIO_AF12_FMC;
    gpio_init.Pin = FMC_SDRAM_SDNWE_PIN;
    HAL_GPIO_Init(FMC_SDRAM_SDNWE_PORT, &gpio_init);
    /* FMC SDCLK */
    gpio_init.Alternate = GPIO_AF12_FMC;
    gpio_init.Pin = FMC_SDRAM_SDCLK_PIN;
    HAL_GPIO_Init(FMC_SDRAM_SDCLK_PORT, &gpio_init);
}


static void _fmc_sdram_delay(uint32_t time)
{
    uint32_t i = 0;
    for(i = 0; i < time; ++i)
        ;
}
